package com.liser.southernstar.utils;

import java.io.ByteArrayOutputStream;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

import javax.crypto.Cipher;

/**
 * RSA256加解密
 */
public class RSA256Encipher {
    private static final String utf8 = "UTF-8";
    /**
     * 加密算法RSA
     */
    private static final String KEY_ALGORITHM = "RSA";
    /*** RSA最大加密明文大小*/
    private static final int MAX_ENCRYPT_BLOCK = 117;
    /*** RSA最大解密密文大小*/
    private static final int MAX_DECRYPT_BLOCK = 256;

    /**
     * 公钥加密
     *
     * @param content 待加密内容
     * @param rsaKey  密钥
     * @return 密文内容
     */
    public static byte[] encrypt(String content, RSA256KeyGenerator.RSAKey rsaKey) {
        ByteArrayOutputStream out = null;
        try {
            KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
            PublicKey pubKey = keyFactory.generatePublic(new X509EncodedKeySpec(rsaKey.getPublicKey()));
            Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
            cipher.init(Cipher.ENCRYPT_MODE, pubKey);
            byte[] data = content.getBytes(utf8);
            int inputLen = data.length;
            out = new ByteArrayOutputStream();
            int offSet = 0;
            byte[] cache;
            int i = 0;
            // 对数据分段加密
            while (inputLen - offSet > 0) {
                if (inputLen - offSet > MAX_ENCRYPT_BLOCK) {
                    cache = cipher.doFinal(data, offSet, MAX_ENCRYPT_BLOCK);
                } else {
                    cache = cipher.doFinal(data, offSet, inputLen - offSet);
                }
                out.write(cache, 0, cache.length);
                i++;
                offSet = i * MAX_ENCRYPT_BLOCK;
            }
            // 生成加密结果
            out.flush();
            return out.toByteArray();
        } catch (Exception ex) {
            throw new RuntimeException("RSA加密失败", ex);
        } finally {
            if (out != null) {
                try {
                    out.close();
                } catch (Exception ex) {
                }
            }
        }
    }

    /**
     * 私钥解密
     *
     * @param encryptedData 待解密内容
     * @param rsaKey        密钥
     * @return 明文内容
     */
    public static String decrypt(byte[] encryptedData, RSA256KeyGenerator.RSAKey rsaKey) {
        ByteArrayOutputStream out = null;
        try {
            KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
            PrivateKey priKey = keyFactory.generatePrivate(new PKCS8EncodedKeySpec(rsaKey.getPrivateKey()));
            Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); // 解密时不指定填充格式将导致安卓环境的乱码。当时对应加密环境为.NET3.5
            cipher.init(Cipher.DECRYPT_MODE, priKey);
            int inputLen = encryptedData.length;
            out = new ByteArrayOutputStream();
            int offSet = 0;
            byte[] cache;
            int i = 0;
            // 对数据分段解密
            while (inputLen - offSet > 0) {
                if (inputLen - offSet > MAX_DECRYPT_BLOCK) {
                    cache = cipher.doFinal(encryptedData, offSet, MAX_DECRYPT_BLOCK);
                } else {
                    cache = cipher.doFinal(encryptedData, offSet, inputLen - offSet);
                }
                out.write(cache, 0, cache.length);
                i++;
                offSet = i * MAX_DECRYPT_BLOCK;
            }
            // 生成解密结果
            out.flush();
            return new String(out.toByteArray(), utf8);
        } catch (Exception ex) {
            throw new RuntimeException("RSA解密失败", ex);
        } finally {
            if (out != null) {
                try {
                    out.close();
                } catch (Exception ex) {
                }
            }
        }
    }
}
